package com.example.service.impl;

import cn.undraw.util.ConvertUtils;
import cn.undraw.util.StrUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.domain.dto.LikedDTO;
import com.example.domain.entity.Comment;
import com.example.domain.entity.CommentLike;
import com.example.mapper.CommentLikeMapper;
import com.example.service.CommentLikeService;
import com.example.service.CommentService;
import com.example.util.redis.RedisUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author readpage
 * @since 2023-02-03 16:15
 */
@Service
public class CommentLikeServiceImpl extends ServiceImpl<CommentLikeMapper, CommentLike> implements CommentLikeService {
    @Resource
    private CommentLikeMapper commentLikeMapper;
    
    @Resource
    private CommentService commentService;

    @Resource
    private RedisUtil redisUtil;

    /**
     * 获取评论点赞key
     * @param uid 用户id
     * @return
     */
    public String getCommentLikeKey(Long uid) {
        return String.format("comment-like:%d:comment-id", uid);
    }

    /**
     * 获取评论点赞数量key
     * @param commentId 评论id
     * @return
     */
    public String getCommentLikeCountKey(Long commentId) {
        return String.format("comment-like:%d:count", commentId);
    }

    @Override
    public int isLiked(LikedDTO likedDTO) {
        // 用户id
        String COMMENT_LIKE = getCommentLikeKey(likedDTO.getUid());
        // 查询redis中是否点赞
        Boolean state = redisUtil.sHasKey(COMMENT_LIKE, likedDTO.getCommentId());
        if (state) {
            return 1;
        } else {
            // redis中没有点赞，查询redis是否取消点赞
            boolean cancel = redisUtil.sHasKey(COMMENT_LIKE, -likedDTO.getCommentId());
            // 如果没取消点赞，查询mysql是否点赞
            if (!cancel) {
                CommentLike commentLike = this.getByLikedDTO(likedDTO);
                // commentLike不等于null，mysql点赞了
                return commentLike != null ? 2 : 0;
            }
        }
        return 0;
    }

    @Override
    public boolean liked(LikedDTO likedDTO) {
        String COMMENT_LIKE = getCommentLikeKey(likedDTO.getUid());
        String COMMENT_LIKE_COUNT = getCommentLikeCountKey(likedDTO.getCommentId());
        // 查询用户是否点赞 int 2: mysql点赞 1: redis点赞 0: 不点赞
        int state = this.isLiked(likedDTO);
        switch (state) {
            case 2:
                // mysql取消点赞
                redisUtil.execute(e -> {
                    e.sSet(COMMENT_LIKE, -likedDTO.getCommentId());
                    e.incr(COMMENT_LIKE_COUNT, -1);
                });
                break;
            case 1:
                // redis取消点赞
                redisUtil.execute(e -> {
                    e.sRemove(COMMENT_LIKE, likedDTO.getCommentId());
                    e.incr(COMMENT_LIKE_COUNT, -1);
                });
                break;
            case 0:
                // redis点赞
                redisUtil.execute(e -> {
                    e.sSet(COMMENT_LIKE, likedDTO.getCommentId());
                    e.incr(COMMENT_LIKE_COUNT, 1);
                });
                break;
        }
        return true;
    }

    @Override
    public int getLikeCount(Long commentId) {
        String COMMENT_LIKE_COUNT = getCommentLikeCountKey(commentId);
        Integer o = redisUtil.get(COMMENT_LIKE_COUNT, Integer.class);
        return StrUtils.isNull(o, 0);
    }

    @Override
    public List<Long> cidListByUid(Long uid) {
        List<Long> list = new ArrayList<>();

        // 获取redis中评论点赞评论Id列表
        String COMMENT_LIKE = getCommentLikeKey(uid);
        Set<Long> set = redisUtil.sGet(COMMENT_LIKE, Long.class);
        // 点赞评论id列表
        List<Long> trueCidList = new ArrayList<>();
        // 取消评论点赞评论id列表 redis存储的值: 评论id的负数
        List<Long> falseCidList = new ArrayList<>();
        for (Long cid : set) {
            if (cid > 0) {
                trueCidList.add(cid);
            } else {
                falseCidList.add(-cid);
            }
        }
        // mysql中的评论id
        List<CommentLike> mysqlCLikeList = commentLikeMapper.selectList(
                new QueryWrapper<CommentLike>()
                        .eq("uid", uid)
        );
        // 去除mysql在redis中取消点赞对应的评论id
        List<Long> mysqlCidList = mysqlCLikeList.stream().map(t -> t.getCommentId()).filter(t -> !falseCidList.contains(t)).collect(Collectors.toList());

        list.addAll(trueCidList);
        list.addAll(mysqlCidList);
        return list;
    }

    @Override
    @Transactional
    public boolean syncLike() {
        // 评论点赞数量列表
        List<Comment> commentList = new ArrayList<>();
        List<String> keys = redisUtil.scan("comment-like:*:count");
        for (String key : keys) {
            String[] split = key.split(":");
            Long articleId = ConvertUtils.toLong(split[1]);
            Integer n = redisUtil.get(key, Integer.class);
            redisUtil.del(key);
            n = StrUtils.isNull(n, 0);
            Comment comment = new Comment();
            comment.setId(articleId);
            comment.setLikes(n);
            commentList.add(comment);
        }

        // 点赞评论列表
        List<CommentLike> trueLikeList = new ArrayList<>();
        // 取消评论点赞评论列表 redis存储的值: 评论id的负数; 取值: uid+cid 用户id+评论id key
        List<String> falseLikeList = new ArrayList<>();
        List<String> keys2 = redisUtil.scan("comment-like:*:comment-id");
        for (String key : keys2) {
            String[] split = key.split(":");
            Long uid = ConvertUtils.toLong(split[1]);
            Set<Long> cList = redisUtil.sGet(key, Long.class);
            for (Long cid : cList) {
                CommentLike commentLike = new CommentLike();
                commentLike.setCommentId(cid);
                commentLike.setUid(uid);
                if (cid > 0) {
                    trueLikeList.add(commentLike);
                } else {
                    String str = String.format("%d%d", commentLike.getUid(), Math.abs(commentLike.getCommentId()));
                    falseLikeList.add(str);
                }
                redisUtil.sRemove(key, cid);
            }
        }

        // mysql取消点赞
        ConvertUtils.batchList(falseLikeList).forEach(e -> {
            this.removeBatchByCid(e);
        });
        // mysql点赞
        this.saveNodupBatch(trueLikeList);

        //修改点赞数量
        commentService.updateBatchById(commentList);
        return true;
    }

    @Override
    public List<String> getKeyList(List<String> list) {
        if (StrUtils.isEmpty(list)) return new ArrayList<>();
        return commentLikeMapper.selectKeyList(list);
    }

    @Override
    public boolean saveNodupBatch(List<CommentLike> list) {
        ConvertUtils.batchList(list).forEach(e -> {
            List<String> keys = list.stream().map(t -> t.getKey()).collect(Collectors.toList());
            List<String> keyList = getKeyList(keys);
            List<CommentLike> nodupList = list.stream().filter(t -> !keyList.contains(t.getKey())).collect(Collectors.toList());
            // mysql点赞
            this.saveBatch(nodupList);
        });
        return true;
    }

    @Override
    public boolean removeBatchByCid(List<String> list) {
        return commentLikeMapper.deleteBatchByCid(list) > 0;
    }

    /**
     * 获取mysql点赞状态
     * @param likedDTO
     * @return com.example.entity.CommentLike
     */
    private CommentLike getByLikedDTO(LikedDTO likedDTO) {
        // 获取mysql中的点赞状态
        return commentLikeMapper.selectOne(
                new QueryWrapper<CommentLike>()
                        .eq("uid", likedDTO.getUid())
                        .eq("comment_id", likedDTO.getCommentId())
        );
    }

}
